package com.blog.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.blog.config.BlogConfig;
import com.blog.entity.SysUser;
import com.blog.service.SysArticleService;
import com.blog.service.SysUserService;
import com.blog.util.laydto.LayDto;
import com.blog.util.laydto.LayDtoUtil;
import com.blog.mapper.SysUserMapper;
import com.blog.redis.RedisUtil;
import com.blog.service.EmailService;
import com.blog.util.*;
import com.blog.util.dto.AjaxResult;
import com.blog.util.md5.MD5Util;
import com.blog.util.uuid.UUIDUtils;
import com.blog.util.xmSelect.XmSelectData;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.websocket.server.PathParam;
import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.blog.common.StandardChar.PASSWORD_LENGTH;
import static com.blog.redis.RedisKeys.KEY_USER_TABLE;

/**
 * 用户控制类
 * @author cgx
 * @Date 2021/8/14 21:46
 */
@Slf4j
@Controller
@RequestMapping("user")
public class SysUserController {

    @Resource
    SysUserMapper userMapper;

    @Resource
    SysUserService userService;

    @Resource
    EmailService emailService;

    @Resource
    RedisUtil redisUtil;

    @Resource
    SysArticleService articleService;

    /**
     *
     * 后台登录功能
     *
     * @param
     * @return
     */
    @PostMapping("/login")
    @ResponseBody
    public AjaxResult login(@RequestParam("username") String username, @RequestParam("password") String password,@PathParam("rememberMe") Boolean rememberMe) {
        if (username.isEmpty()){
            return AjaxResult.error("用户名为空");
        }
        if (password.isEmpty()){
            return AjaxResult.error("密码为空");
        }
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, MD5Util.getMd5(password, BlogConfig.getMd5Key()),rememberMe);
        try {
            subject.login(token);
            return AjaxResult.success(username);
            //用户名错误
        } catch (AuthenticationException e){
            String msg = "登录出现错误";
            if (!e.getMessage().isEmpty()){
                msg = e.getMessage();
            }
            return AjaxResult.error(msg);
        }
    }

    /**
     * 邮箱发送验证码
     * @param username 用户名
     * @param email 邮箱
     * @return
     */
    @ResponseBody
    @PostMapping("/registerCode")
    public AjaxResult registerCode(@PathParam("username") String username, @PathParam("email") String email) {
        //获取发送的验证码
        //验证邮箱
        if (!RegularUtil.checkEmail(email)) {
            return AjaxResult.error( "邮箱格式不合法");
        }
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",email);
        List<SysUser> users = userService.list(queryWrapper);
        //假如存在用户
        if (users.size()!=0) {
            return AjaxResult.error( "该邮箱已被绑定，请更换邮箱");
        }

        QueryWrapper<SysUser> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("username",email);
        List<SysUser> sysUsers = userService.list(queryWrapper2);
        if (sysUsers.size()!=0){
            return AjaxResult.error( "该账号已存在");
        }

        String registerCode = String.valueOf(VerifyCodeUtil.getRegisterCode());
        //将验证码保存至redis中
        redisUtil.set(username,registerCode,1800);
        emailService.sendEmail(registerCode, email);
        return AjaxResult.success();
    }
    /**
     * 注册功能
     * @param
     * @return
     */
    @PostMapping("/register")
    @ResponseBody
    public AjaxResult register(@RequestParam("username") String username, @RequestParam("password") String password, @RequestParam("email") String email, @RequestParam("code") String code){
        //用户注册事前之前先删除redis缓存
        redisUtil.del(KEY_USER_TABLE);
        //判断验证码
        if (code.isEmpty()){
            return AjaxResult.error("验证码为空，请重新获取");
        }
        // -2代表不存在，即过期
        if (redisUtil.getExpire(username) == -2){
            return AjaxResult.error("验证码已过期，请重新发送");
        }

        //获取验证码
        String verifyCode = (String) redisUtil.get(username);
        if (verifyCode==null){
            return AjaxResult.error("验证码为空");
        }
        if (!verifyCode.equals(code)){
            return AjaxResult.error("验证码不正确，请重新获取");
        }
        //判断用户名
        if (username.isEmpty()){
            return AjaxResult.error("用户名为空");
        }
        //判断密码
        if (password.isEmpty()){
            return AjaxResult.error("密码为空");
        }
        if (password.length() < PASSWORD_LENGTH){
            return AjaxResult.error("密码长度必须为6位或者6位以上");
        }
        //判断邮箱
        if (email.isEmpty()){
            return AjaxResult.error("邮箱不能为空");
        }
        if (!RegularUtil.checkEmail(email)){
            return AjaxResult.error( "邮箱格式不合法");
        }
        SysUser sysUser = new SysUser();
        sysUser.setId(UUIDUtils.getUUId());
        sysUser.setUsername(username);
        sysUser.setPassword(MD5Util.getMd5(password,BlogConfig.getMd5Key()));
        sysUser.setEmail(email);
        sysUser.setNickname("用户"+UUIDUtils.getUUId().substring(0,8));
        sysUser.setType("1");
        sysUser.setActive(1);
        userMapper.insert(sysUser);
        return AjaxResult.success();
    }

    /**
     * 后台用户修改个人信息
     *
     * @param
     * @return
     */
    @PostMapping("/updatePerson/Information")
    @ResponseBody
    public AjaxResult updatePersonInformation(@PathParam("userId") String userId, @PathParam("username") String username, @PathParam("description") String description, @PathParam("address") String address, @PathParam("userSex") Integer sex,HttpSession session) {
        //修改数据之前先删除redis缓存
        redisUtil.del(KEY_USER_TABLE);
        if (username.isEmpty()) {
            return AjaxResult.error( "用户名为空");
        }
        if (description.isEmpty()) {
            return AjaxResult.error( "个人描述为空");
        }
        if (address.isEmpty()) {
            return AjaxResult.error( "地址为空");
        }
        //查询用户是否存在，更新用户信息
        SysUser sysUser = userMapper.selectById(userId);
        sysUser.setUsername(username);
        sysUser.setDescription(description);
        sysUser.setAddress(address);
        sysUser.setSex(sex);
        boolean save = userService.saveOrUpdate(sysUser);
        session.removeAttribute("user");
        if (!save) {
            return AjaxResult.success(false, "保存失败");
        } else {
            SysUser user = userMapper.selectById(userId);
            session.setAttribute("user", user);
            return AjaxResult.success();
        }
    }

    /**
     * 个人信息主页修改密码
     * @param
     * @return
     */
    @PostMapping("/updatePerson/updatePersonPassword")
    @ResponseBody
    public AjaxResult updatePersonPassword(@PathParam("userid") String userid, @PathParam("oldPassword") String oldPassword, @PathParam("newPassword") String newPassword, @PathParam("newPasswordCheck") String newPasswordCheck,HttpSession session){
        //修改数据之前先删除redis缓存
        redisUtil.del(KEY_USER_TABLE);
        if (oldPassword.isEmpty()){
            return AjaxResult.error("旧密码为空!");
        }
        if (newPassword.isEmpty()){
            return AjaxResult.error("请输入新密码！");
        }
        if (newPasswordCheck.isEmpty()){
            return AjaxResult.error("请输入确认密码！");
        }
        if (!newPasswordCheck.equals(newPassword)){
            return AjaxResult.error("两次密码不一致，请检查您的密码！");
        }
        //查询出用户
        SysUser sysUser = userMapper.selectById(userid);
        String userPassword = sysUser.getPassword();
        //比较密码
        boolean b = MD5Util.equalMd5(oldPassword, userPassword, BlogConfig.getMd5Key());
        if (!b){
            return AjaxResult.error("您的密码错误！");
        }
        boolean b1 = MD5Util.equalMd5(newPassword, oldPassword, BlogConfig.getMd5Key());
        if (b1){
            return AjaxResult.error("新密码不能和旧密码相同！");
        }
        //更新密码
        String password = MD5Util.getMd5(newPassword, BlogConfig.getMd5Key());
        sysUser.setPassword(password);
        boolean saveOrUpdate = userService.saveOrUpdate(sysUser);
        session.removeAttribute("user");
        if (!saveOrUpdate){
            return AjaxResult.error("保存失败");
        }else {
            return AjaxResult.success();
        }


    }

    /**
     * 表格数据获取
     * @param
     * @return
     */
    @GetMapping("/admin/table")
    @ResponseBody
    public LayDto table(String username,Integer sex,String emailOrPhone,Long userRoleId){
        List<SysUser> allUser = userService.tableList(username,sex,emailOrPhone,userRoleId);
        return LayDtoUtil.returnSuccess(0, "", allUser.size(), allUser);
    }

    /**
     * 删除数据通过id
     * @param id 用户id
     * @return
     */
    @PostMapping("/table/deleteById")
    @ResponseBody
    public AjaxResult tableDeleteById(@PathParam("id") String id) {
        boolean b = userService.removeById(id);
        if (b) {
            return AjaxResult.success();
        } else {
            return AjaxResult.error( "删除失败");
        }
    }

    /**
     * 通过ids批量删除数据
     * @param deleteIds 用户id
     * @return
     */
    @PostMapping("/table/deleteByIds")
    @ResponseBody
    public AjaxResult tableDeleteByIds(@RequestBody List<String> deleteIds){
        List<SysUser> sysUsers = userService.listByIds(deleteIds);

        //当数据只有一条时
        if (deleteIds.size() == 1){
            SysUser sysUser = userService.getById(deleteIds.get(0));
            if (sysUser.getType() == "all" || "all".equals(sysUser.getType())){
                return AjaxResult.error("本条数据您没有权限删除");
            }
        }
        //很多数据的时候
        for (int i = 0; i < sysUsers.size(); i++) {
            if (sysUsers.get(i).getType() == "0" || "0".equals(sysUsers.get(i).getType())){
                return AjaxResult.error("对不起，"+(i+1)+"条数据您没有权限删除");
            }
        }
        boolean b = userService.removeByIds(deleteIds);
        if (b) {
            return AjaxResult.success();
        } else {
            return AjaxResult.error( "删除失败");
        }
    }

    /**
     * 后台用户注销
     * @param
     * @return
     */
    @GetMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "redirect:/";
    }

    /**
     * 跳转至导出弹框
     * @param
     * @return
     */
    @GetMapping("/table/import")
    public String importUser(){
        return "/admin/user/user-import";
    }

    /**
     * 用户下载导入文件
     * @param
     * @return
     */
    @GetMapping("/table/importFile")
    public void importFile(HttpServletResponse response){
        String titles = "用户名,邮箱,个人描述,电话号,性别";
        List<String> fileTitle = Arrays.asList(titles.split(","));
        //创建一个工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();
        //创建一个sheet
        HSSFSheet sheet = workbook.createSheet("用户信息表");
        //设置表格列宽度为10个字节
        sheet.setDefaultColumnWidth(15);
        //创建第一行（模板，只需要第一行即可）
        HSSFRow headrow = sheet.createRow(0);
        for (int i = 0; i < fileTitle.size(); i++) {
            //创建一个单元格
            HSSFCell cell = headrow.createCell(i);
            //创建一个内容对象
            String text = fileTitle.get(i);
            //将内容对象的文字内容写入到单元格中
            cell.setCellValue(text);
        }
        String[] strs = new String[] { "男", "女"};
        //设置位置区间
        CellRangeAddressList regions = new CellRangeAddressList(0, 999, fileTitle.size()-1, fileTitle.size()-1);
        //设置内容
        DVConstraint constraint = DVConstraint.createExplicitListConstraint(strs);
        HSSFDataValidation dataValidation = new HSSFDataValidation(regions, constraint);

        sheet.addValidationData(dataValidation);
        response.setContentType("application/octet-stream");

        //workbook将Excel写入到response的输出流中，供页面下载
        String fileName = "用户导入模板";
        try (OutputStream out = response.getOutputStream()) {
            String finalFileName = new String(fileName.getBytes(), "ISO8859-1");
            response.setHeader("Content-disposition", "attachment;filename="+finalFileName+".xls");
            workbook.write(out);
            out.flush();
        } catch (IOException e) {
            log.error(e.getMessage(),e);
        }finally{

            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }


    /**
     * 解析导入文件，存入数据库中
     * @param
     * @return
     */
    @PostMapping("/table/uploadUserExcel")
    @ResponseBody
    public AjaxResult uploadUserExcel(MultipartFile file) throws Exception{
        //导入数据之前先删除redis缓存
        redisUtil.del(KEY_USER_TABLE);

        String[] headers = {"用户名","邮箱","个人描述","电话号","性别"};
        InputStream inputStream = file.getInputStream();
        Workbook workbook = new HSSFWorkbook(inputStream);
        //获取第一个sheet
        Sheet sheet = workbook.getSheetAt(0);
        int rowsNumber = sheet.getPhysicalNumberOfRows();
        //获取第一行数据(标题行)
        Row rowTitle = sheet.getRow(0);
        //获取每一列的单元格个数
        int cellsCount = rowTitle.getPhysicalNumberOfCells();

        if (headers.length != cellsCount){
            return AjaxResult.error("列数不匹配");
        }
        //判断标题是否对应
        for (int i = 0; i < headers.length; i++) {
            String currentCellTitle = rowTitle.getCell(i).getStringCellValue();
            if (!headers[i].equals(currentCellTitle)){
                return AjaxResult.error("第"+(i+1)+"列标题不正确");
            }
        }

        AjaxResult parseDto = userService.parseExcelData(workbook,headers);

        if (parseDto.getMsg()!= null){
            if (!(parseDto.getMsg().isEmpty())){
                return AjaxResult.error( parseDto.getMsg());
            }
        }
        List<SysUser> data = (List<SysUser>)parseDto.getData();
        //判断data中有没有重复数据
        int count = 0;
        for (int i = 0; i < data.size(); i++) {
            for (int j = i+1; j < data.size(); j++) {
                if (data.get(i).getUsername().equals(data.get(j).getUsername())){
                    count++;
                }
            }
        }
        if (count == 0){
            userService.saveBatch(data);
            return AjaxResult.success();
        }else {
            return AjaxResult.error(count+"条数据重复");
        }
    }

    /**
     * 修改页面跳转
     * @param
     * @return
     */
    @GetMapping("/admin/changeAvatar")
    public String changeAvatar(){
        return "admin/user/public/change-avater";
    }

    /**
     * 个人中心跳转
     * @param
     * @return
     */
    @GetMapping("/index/personCenter")
    public String toPersonCenter(){
        return "user/person-center";
    }

    /**
     * 编辑基本资料页面跳转
     * @param
     * @return
     */
    @GetMapping("/index/editMaterial")
    public String editMaterial(){
        return "user/public/user-material";
    }

    /**
     * 保存用户基本资料
     * @param
     * @return
     */
    @PostMapping("/index/saveMaterial")
    @ResponseBody
    public AjaxResult saveMaterial(HttpServletRequest request,HttpSession session){
        String userId = request.getParameter("userId");
        String nickname = request.getParameter("nickname");
        String email = request.getParameter("email");
        String description = request.getParameter("description");
        String phone = request.getParameter("phone");
        String address = request.getParameter("address");
        String sex = request.getParameter("sex");


        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("nickname",nickname);
        List<SysUser> list = userService.list(queryWrapper);
        if (list.size() != 0){
            return AjaxResult.error("改昵称已存在");
        }

        QueryWrapper<SysUser> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("email",email);
        List<SysUser> list1 = userService.list(queryWrapper2);
        if (list1.size() > 1){
            return AjaxResult.error("该邮箱已存在");
        }

        session.removeAttribute("user");
        SysUser sysUser = userService.getById(userId);
        sysUser.setNickname(nickname);
        sysUser.setEmail(email);
        sysUser.setDescription(description);
        sysUser.setPhone(phone);
        sysUser.setAddress(address);
        sysUser.setSex(Integer.valueOf(sex));
        boolean b = userService.updateById(sysUser);
        if (b){
            session.setAttribute("user",sysUser);
            return AjaxResult.success();
        }else {
            return AjaxResult.error("保存失败");
        }
    }

    /**
     * 首页个人中心查询博客数量
     * @param
     * @return
     */
    @GetMapping("/index/queryArticleCount")
    @ResponseBody
    public AjaxResult queryArticleCount(){
        SysUser sysUser = (SysUser)SecurityUtils.getSubject().getPrincipal();
        Map<String,Object> queryMap = new HashMap<>();
        queryMap.put("authorId",sysUser.getId());
        Map<String,Object> map = articleService.queryArticleCount(queryMap);
        return AjaxResult.success(map);
    }

    /**
     * 编辑教育经历页面跳转
     * @param
     * @return
     */
    @GetMapping("/index/editEducation")
    public String editEducation(){
        return "user/public/user-education";
    }

    /**
     * 保存用户教育经历
     * @param
     * @return
     */
    @PostMapping("/index/saveEducation")
    @ResponseBody
    public AjaxResult saveEducation(HttpServletRequest request,HttpSession session){
        String userId = request.getParameter("userId");
        String eduSchool = request.getParameter("eduSchool");
        String eduSubject = request.getParameter("eduSubject");
        String eduTime = request.getParameter("eduTime");
        String eduGrade = request.getParameter("eduGrade");

        session.removeAttribute("user");
        SysUser sysUser = userService.getById(userId);
        sysUser.setEduSchool(eduSchool);
        sysUser.setEduSubject(eduSubject);
        sysUser.setEduTime(eduTime);
        Map<String, String> grade = getEduGrade();
        String s = grade.get(eduGrade);
        sysUser.setEduGrade(s);

        boolean b = userService.updateById(sysUser);
        if (b){
            session.setAttribute("user",sysUser);
            return AjaxResult.success();
        }else {
            return AjaxResult.error("保存失败");
        }
    }

    public Map<String,String> getEduGrade(){
        Map<String,String> map = new HashMap<>();
        map.put("01","博士");
        map.put("02","硕士");
        map.put("03","本科");
        map.put("04","专科");
        map.put("05","高中");
        map.put("06","高中以下");
        return map;
    }


    @GetMapping("/admin/getRoleSelect")
    @ResponseBody
    public AjaxResult getRoleSelect(@RequestParam(value = "userId",required = false) String userId){
        List<XmSelectData> xmSelectData = userService.getRoleXmSelect(userId);
        return AjaxResult.success(xmSelectData);
    }

    @GetMapping("/admin/add")
    public String userAdd(){
        return "admin/user/user-add";
    }

    @PostMapping("/admin/saveUser")
    @ResponseBody
    public AjaxResult saveUser(@RequestBody SysUser user){
        userService.saveUser(user);
        return AjaxResult.success(user);
    }

    @GetMapping("/admin/user-edit")
    public String userEdit(@RequestParam("userId") String userId, Model model){
        model.addAttribute("userId",userId);
        return "admin/user/user-edit";
    }


    @GetMapping("/admin/queryUser")
    @ResponseBody
    public AjaxResult queryUser(@RequestParam("userId") String userId){
        SysUser byId = userService.getById(userId);
        return AjaxResult.success(byId);
    }

    @PostMapping("/admin/updateUser")
    @ResponseBody
    public AjaxResult updateUser(@RequestBody SysUser user){
        userService.updateById(user);
        return AjaxResult.success(user);
    }
}



